package com.app.business.service;

import com.app.business.calculate.CalculateUtils;
import com.app.business.en.HouseStatus;
import com.app.business.en.Status;
import com.app.business.model.*;
import com.app.business.utils.UserPermissionUtil;
import com.app.system.jpa.JpaBaseDao;
import com.app.system.jpa.PageBean;
import com.app.system.jpa.Wrapper;
import com.app.system.permission.model.UserInfo;
import com.app.system.permission.service.UserInfoService;
import com.app.system.utils.CollectionUtils;
import com.app.system.utils.ParamUtils;
import com.app.system.utils.WebUtils;
import com.app.system.utils.exception.Precondition;
import com.app.system.utils.exception.Response;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.collect.Maps;
import org.apache.shiro.SecurityUtils;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * Created by ddz on 2021/12/01.
 * 商铺业务层
 *
 * @author lsh
 */
@SuppressWarnings(value = "ALL")
@Service
public class ShopHouseService extends JpaBaseDao<ShopHouse, Integer> {

    @Autowired
    private AzProjectService azProjectService;
    @Autowired
    private HouseService houseService;
    @Autowired
    private ContractService contractService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private ActionHistoryService actionHistoryService;
    @Autowired
    private UserInfoForPropertyService userInfoForPropertyService;


    /**
     * 分页处理
     *
     * @return
     */
    public PageBean<ShopHouse> shopHouseListByProjectId(Integer projectId) {
        //查询语句
        StringBuffer query = new StringBuffer(" s from ShopHouse s inner join fetch s.azProject p ");

        //默认排序(PageBean指定排序字段类型的话，则默认排序不使用)
        StringBuffer orderBy = new StringBuffer(" s.houseStatus,s.buildNum,s.houseNum");
        Wrapper wrapper = new Wrapper(query, orderBy);
        wrapper.initSearchParams();
        wrapper.andEq("p.id", projectId);
        return this.pageHql(wrapper);
    }

    /**
     * 分页处理
     *
     * @return
     */
    public PageBean<ShopHouse> shopHouseExcelListByProjectId(Integer projectId) {
        //查询语句
        StringBuffer query = new StringBuffer("  s from ShopHouse s inner join fetch s.azProject p  ");

        //默认排序(PageBean指定排序字段类型的话，则默认排序不使用)
        StringBuffer orderBy = new StringBuffer(" p.id,s.buildNum,s.houseNum");
        PageBean pageBean = new PageBean();
        pageBean.setPageSize(Integer.MAX_VALUE);
        Wrapper wrapper = new Wrapper(pageBean, query, null, orderBy);
        wrapper.initSearchParams();
        wrapper.andEq("p.id", projectId);
        return this.pageHql(wrapper);
    }

    /**
     * 通过安置项目id获取所有 具有唯一性的 商铺信息
     * Set<安置项目id-幢号-户号-所在层数>
     *
     * @param azProjectId
     * @return
     */
    public Set<String> findShopHouseSetByAzProjectId(Integer azProjectId) {
        StringBuffer hql = new StringBuffer("select CONCAT(s.az_project_id,'-',s.build_num,'-',s.house_num,'-',s.floor) from Shop_House s");
        hql.append(" where s.az_project_id =:azProjectId ");
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("azProjectId", azProjectId);
        List<String> list = this.findSqlObject(hql.toString(), map);
        Set<String> resultSet = Sets.newHashSet();
        if (CollectionUtils.isNotEmpty(list)) {
            for (String houseString : list) {
                resultSet.add(houseString);
            }
        }
        return resultSet;
    }


    /**
     * 所有安置项目得到商铺数量(总计，已选)
     *
     * @param azProjectId
     * @return
     */
    public Map<String, Map> getShopHouseCountMap() {
        StringBuffer sql = new StringBuffer("select s.az_project_id as azProjectId,ifnull(COUNT(s.id),0) as shopHouseTotal,");
        sql.append("ifnull(sum(case when s.house_status =2 then 1 else 0 end),0) as signShopHouse,");
        sql.append("ifnull(sum(case when s.take_house_status =2 then 1 else 0 end),0) as takeShopHouseCount");
        sql.append(" from shop_house s group by s.az_project_id order by s.az_project_id");
        Query query = this.entityManager.createNativeQuery(sql.toString());
        List<Map> mapList = query.unwrap(org.hibernate.SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
        Map<String, Map> storageRoomCountMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(mapList)) {
            for (Map map : mapList) {
                String azProjectId = map.get("azProjectId").toString();
                storageRoomCountMap.put(azProjectId, map);
            }
        }
        return storageRoomCountMap;
    }

    /**
     * 查询某协议下所有的已选房源
     *
     * @param contractId
     * @return
     */
    public List<ShopHouse> getShopHouseListByContractId(Integer contractId) {
        StringBuffer hql = new StringBuffer("from ShopHouse s inner join fetch s.azProject azp where s.contract.id = :contractId order by s.chooseHouseDate");
        List<ShopHouse> shopHouseList = entityManager.createQuery(hql.toString()).setParameter("contractId", contractId).getResultList();
        return shopHouseList;
    }


    /**
     * 通过f房源idList获取某些房源
     *
     * @param houseIdList
     * @return
     */
    public List<ShopHouse> getShopHouseListByIds(String shopHouseIdStr) {
        StringBuffer hql = new StringBuffer("from ShopHouse sr inner join fetch sr.azProject azp where sr.id in (" + shopHouseIdStr + ") order by sr.chooseHouseDate");
        List<ShopHouse> shopHouseList = entityManager.createQuery(hql.toString()).getResultList();
        return shopHouseList;
    }

    /**
     * 得到某些协议所对应的商铺，并封装map
     *
     * @param contractIdList
     * @return
     */
    public Map<Integer, List<ShopHouse>> getShopHouseMapByContractIdList(List<Integer> contractIdList) {
        StringBuffer hql = new StringBuffer("from ShopHouse s inner join fetch s.contract c where c.id in (:contractIdList) order by s.buildNum,s.houseNum ");
        List<ShopHouse> shopHouseList = entityManager.createQuery(hql.toString()).setParameter("contractIdList", contractIdList).getResultList();
        Map<Integer, List<ShopHouse>> resultMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(shopHouseList)) {
            List<ShopHouse> itemList = Lists.newLinkedList();
            for (ShopHouse shopHouse : shopHouseList) {
                itemList = null;
                itemList = resultMap.get(shopHouse.getContract().getId()) == null ? Lists.newLinkedList() : resultMap.get(shopHouse.getContract().getId());
                itemList.add(shopHouse);
                resultMap.put(shopHouse.getContract().getId(), itemList);
            }
        }
        return resultMap;
    }

    /**
     * 商铺保存
     *
     * @param request
     * @return
     */
    @Transactional
    public synchronized Response shopHouseSave(HttpServletRequest request) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        Integer shopHouseId = ParamUtils.getInt(request, "shopHouseId", 0);
        Integer contractId = ParamUtils.getInt(request, "contractId", 0);
        ShopHouse shopHouse = this.findOne(shopHouseId);
        Contract contract = contractId == 0 ? shopHouse.getContract() : this.contractService.findOne(contractId);
        Precondition.checkAjaxArguement(contract != null && shopHouse != null, "1111", "数据错误！");
        Precondition.checkAjaxArguement(contract.getLimitStatus() != null && contract.getLimitStatus().equals(Status.NO.getIndex()), "4444", "该家庭当前暂不能选择店铺！");
        Precondition.checkAjaxArguement(contract.getChooseHouseStatus().equals(Status.NO.getIndex()), "2222", "该协议已选房签认，不能选择店铺！");
        Precondition.checkAjaxArguement(shopHouse.getHouseStatus().equals(HouseStatus.KEXUAN.getIndex()), "2222", "该店铺已被选，请刷新确认！");

        shopHouse.setHouseStatus(HouseStatus.YIXUAN.getIndex());   //已选
        shopHouse.setChooseHouseDate(new Date());   //选房时间
        shopHouse.setChoosePerson(this.userInfoService.findByUsername(SecurityUtils.getSubject().getPrincipal().toString()).getName());   //操作人
        shopHouse.setContract(contract);
        this.save(shopHouse);
        this.actionHistoryService.saveActionHistoryByContractId(contract.getId(), "选择店铺" + shopHouse.getHouseNumStr(), "选择店铺");

        CalculateUtils.main(contract.getId());
        return new Response("0001", "保存成功！");
    }

    /**
     * 商铺撤销
     *
     * @param request
     * @return
     */
    @Transactional
    public synchronized Response shopHouseDelete(HttpServletRequest request) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Integer shopHouseId = ParamUtils.getInt(request, "shopHouseId", 0);
        ShopHouse shopHouse = this.findOne(shopHouseId);
        Contract contract = shopHouse.getContract();
        Precondition.checkAjaxArguement(shopHouse != null && contract != null, "1111", "数据错误！");
        Precondition.checkAjaxArguement(contract.getLimitStatus() != null && contract.getLimitStatus().equals(Status.NO.getIndex()), "4444", "该家庭当前暂不能撤销店铺！");
        Precondition.checkAjaxArguement(contract.getChooseHouseStatus().equals(Status.NO.getIndex()), "2222", "该协议已选房签认，不能撤销店铺！");
        Precondition.checkAjaxArguement(shopHouse.getHouseStatus().equals(HouseStatus.YIXUAN.getIndex()), "3333", "该店铺已经撤销，请勿重复操作！");
        shopHouse.setHouseStatus(HouseStatus.KEXUAN.getIndex());   //可选
        shopHouse.setChooseHouseDate(null);   //选房时间
        shopHouse.setChoosePerson(null);   //操作人
        shopHouse.setContract(null);
        this.save(shopHouse);
        this.actionHistoryService.saveActionHistoryByContractId(contract.getId(), "撤销店铺" + shopHouse.getHouseNumStr(), "撤销店铺");
        CalculateUtils.main(contract.getId());
        return new Response("0001", "撤销成功！");
    }

    /**
     * 分页处理（根据征收项目，得到所分配的安置项目以及商铺）
     *
     * @return
     */
    public PageBean<ShopHouse> getShopHousePageByZsProjectId(Integer zsProjectId) {
        List<String> azProjectIdList = this.houseService.getAzProjectIdListByZsProjectId(zsProjectId);
        //如果查出是空，存入一个id0，防止in查询报错
        if (CollectionUtils.isEmpty(azProjectIdList)) {
            azProjectIdList.add("0");
        }
        //查询语句
        StringBuffer query = new StringBuffer(" s from ShopHouse s inner join fetch s.azProject ap ");
        //默认排序(PageBean指定排序字段类型的话，则默认排序不使用)
        StringBuffer orderBy = new StringBuffer(" ap.id,s.houseStatus,s.buildNum,s.floor,s.houseNum");
        Wrapper wrapper = new Wrapper(query, orderBy);
        wrapper.initSearchParams();
        wrapper.andIn("ap.id", azProjectIdList);
        return this.pageHql(wrapper);
    }

    /**
     * 已选商铺明细分页处理
     *
     * @return
     */
    public PageBean<ShopHouse> getSelectedShopHousePageBean() {
        //查询语句
        StringBuffer query = new StringBuffer("s from ShopHouse s inner join fetch s.contract c inner join fetch c.zsProject zsp  inner join fetch s.azProject azp");

        //默认排序(PageBean指定排序字段类型的话，则默认排序不使用)
        StringBuffer orderBy = new StringBuffer("zsp.id,c.id,s.id");
        Wrapper wrapper = new Wrapper(query, orderBy);
        wrapper.initSearchParams();
        wrapper.andEq("s.houseStatus", Status.YES.getIndex());

        UserPermissionUtil.zsProjectUserLimit(wrapper);        //用户只能看到已经分配给自己的项目下的协议信息

        return this.pageHql(wrapper);
    }

    /**
     * 已选商铺明细导出，不分页
     *
     * @return
     */
    public PageBean<ShopHouse> getExcelSelectedShopHousePageBean() {
        //查询语句
        StringBuffer query = new StringBuffer("s from ShopHouse s inner join fetch s.contract c inner join fetch c.zsProject zsp  inner join fetch s.azProject azp inner join fetch s.house h");

        //默认排序(PageBean指定排序字段类型的话，则默认排序不使用)
        StringBuffer orderBy = new StringBuffer("zsp.id,c.id,s.id");
        PageBean pageBean = new PageBean();
        pageBean.setPageSize(Integer.MAX_VALUE);
        Wrapper wrapper = new Wrapper(pageBean, query, null, orderBy);
        wrapper.andEq("s.houseStatus", Status.YES.getIndex());

        wrapper.initSearchParams();
        UserPermissionUtil.zsProjectUserLimit(wrapper);        //用户只能看到已经分配给自己的项目下的协议信息

        return this.pageHql(wrapper);
    }

    /**
     * 档案已发放商铺明细分页处理
     * 交房列表
     *
     * @return
     */
    public PageBean<ShopHouse> getDaffShopHousePageBean() {
        UserInfo userInfo = WebUtils.getLoginUserInfo();
        List<Integer> azProjectIdList = this.userInfoForPropertyService.findAzProjectIdByUserIdAndTowm(userInfo.getId());
        azProjectIdList.add(0);
        //查询语句
        StringBuffer query = new StringBuffer("sr from ShopHouse sr inner join fetch  sr.azProject azp inner join fetch sr.contract c ");
        StringBuffer orderBy = new StringBuffer("sr.takeHouseStatus,azp.id,sr.buildNum,sr.houseNum");
        Wrapper wrapper = new Wrapper(query, orderBy);
        wrapper.initSearchParams();
        wrapper.andEq("sr.houseStatus", Status.YES.getIndex());
        wrapper.andIn("azp.id", azProjectIdList);
        return this.pageHql(wrapper);
    }

    /**
     * 档案已发放商铺明细分页处理
     * 交房列表
     *
     * @return
     */
    public PageBean<ShopHouse> getDaffShopHouseExcelPageBean() {
        UserInfo userInfo = WebUtils.getLoginUserInfo();
        List<Integer> azProjectIdList = this.userInfoForPropertyService.findAzProjectIdByUserIdAndTowm(userInfo.getId());
        azProjectIdList.add(0);
        //查询语句
        StringBuffer query = new StringBuffer("sr from ShopHouse sr inner join fetch  sr.azProject azp inner join fetch sr.contract c ");
        StringBuffer orderBy = new StringBuffer("sr.takeHouseStatus,azp.id,sr.buildNum,sr.houseNum");
        PageBean pageBean = new PageBean();
        pageBean.setPageSize(Integer.MAX_VALUE);
        Wrapper wrapper = new Wrapper(pageBean, query, null, orderBy);
        wrapper.initSearchParams();
        wrapper.andEq("sr.houseStatus", Status.YES.getIndex());
        wrapper.andIn("azp.id", azProjectIdList);
        return this.pageHql(wrapper);
    }

    /**
     * 得到协议id不为空的商铺map
     *
     * @return
     */
    public Map<String, List<ShopHouse>> getShopHouseByContractIdMap() {
        StringBuffer hql = new StringBuffer("from ShopHouse s inner join fetch s.azProject azp where s.contract.id is not null order by s.chooseHouseDate");
        List<ShopHouse> shopHouseList = entityManager.createQuery(hql.toString()).getResultList();

        List<ShopHouse> valueList = null;

        Map<String, List<ShopHouse>> map = Maps.newLinkedHashMap();
        if (CollectionUtils.isNotEmpty(shopHouseList)) {
            for (ShopHouse s : shopHouseList) {
                String id = String.valueOf(s.getContract().getId());
                valueList = map.get(id) == null ? new ArrayList<>() : map.get(id);
                valueList.add(s);
                map.put(id, valueList);
            }
        }
        return map;
    }


    /**
     * 得到安置名称下所协议id
     *
     * @param azProjectName
     * @return
     */
    public List<Integer> getContractIdListByAzProjectName(String azProjectName, String startDate, String stopDate) {
        String sql = "select s.contract_id  from shop_house s inner join az_project azp on s.az_project_id=azp.id ";
        if (azProjectName != null && !azProjectName.equals("")) {
            sql = sql + " where azp.project_name like  '%" + azProjectName + "%'";
        }
        if (startDate != null && startDate != "") {
            sql = sql + " and DATE(s.choose_house_date) >= " + "'" + startDate + "'";
        }
        if (stopDate != null && stopDate != "") {
            sql = sql + " and DATE(s.choose_house_date) <=" + "'" + stopDate + "'";
        }
        return this.entityManager.createNativeQuery(sql)
                .getResultList();
    }
    /**
     * 得到某一年内
     *
     * @param azProjectName
     * @return
     */
    public List<Integer> getShopHouseIdListByChooseHouseDateYear(String yearStr) {
        String sql = "select  s.id  from shop_house s  ";
        sql = sql + " where s.choose_house_date is not null ";
        if (yearStr != null && !yearStr.equals("")) {
            sql = sql + " and YEAR(s.choose_house_date) = " + yearStr;
        }
        return this.entityManager.createNativeQuery(sql)
                .getResultList();
    }
}
